using System;
using System.Collections.Generic;
using System.Text;

namespace OneStop.Calculations
{
    /// <summary>
    /// Models oxygen toxicity.
    /// </summary>
    public class OxTox
    {
        #region Members

        private double cns;
        private double otu;
        private double maxOx;

        #endregion

        #region Properties 

        /// <summary> Gets the maximum ppO2 ecountered</summary>
		/// <returns> Maximum ppO2
		/// </returns>
		/// <summary> Sets Max ppO2 (for Bean Compliance)</summary>
		/// <param name="d">Max ppO2
		/// </param>
		virtual public double MaxOx
		{
			get
			{
				return maxOx;
			}
			
			set
			{
				maxOx = value;
			}
			
		}

        /// <summary> Gets current CNS</summary>
		/// <returns> Current CNS
		/// </returns>
		/// <summary> Sets current CNS (for Bean Compliance)</summary>
		/// <param name="d">Current CNS
		/// </param>
		virtual public double Cns
		{
			get
			{
				return cns;
			}
			
			set
			{
				cns = value;
			}
			
		}

        /// <summary> Gets current OTU</summary>
		/// <returns> Current OTU
		/// </returns>
		/// <summary> Sets current OTU (for Bean Compliance)</summary>
		/// <param name="d">Current OTU
		/// </param>
		virtual public double Otu
		{
			get
			{
				return otu;
			}
			
			set
			{
				otu = value;
			}

        }

        #endregion

        #region Methods

        /// <summary>
        /// Initialise OxTox model.
        /// </summary>
		public virtual void InitialiseOxTox()
		{
			cns = 0;
			otu = 0;
			maxOx = 0;
		}

		/// <summary> 
        /// Adds oxygen load into model. Uses NOAA lookup table to add 
        /// percentage based on time and ppO2.
        /// </summary>
		/// <param name="pO2">Partial pressure of oxygen in atm (not msw!)</param>
		/// <param name="time">Time of segment in minutes</param>
		public virtual void AddO2(double time, double pO2)
		{
			//assert(time >0 && pO2 >= 0 && pO2 <= 5.0);
			double d;
			double exposure; // == mins for cns==100%

			// Calculate OTU using formula OTU= T * (0.5/(pO2-0.5))^-(5/6)
			if (pO2 > 0.5)
			{
				// Only accumulate OTUs for ppO2 >= 0.5 atm
				d = time * System.Math.Pow((0.5 / (pO2 - 0.5)), - 0.833333);
				otu += d;
			}

			// CNS Calculations
			if (pO2 > 1.8)
				exposure = 1;
			// Need a better figure here
			else if (pO2 > 1.7)
				exposure = 4;
			else if (pO2 > 1.6)
				exposure = 12;
			else if (pO2 > 1.5)
				exposure = 45;
			else if (pO2 > 1.4)
				exposure = 120;
			else if (pO2 > 1.3)
				exposure = 150;
			else if (pO2 > 1.2)
				exposure = 180;
			else if (pO2 > 1.1)
				exposure = 210;
			else if (pO2 > 1.0)
				exposure = 240;
			else if (pO2 > 0.9)
				exposure = 300;
			else if (pO2 > 0.8)
				exposure = 360;
			else if (pO2 > 0.7)
				exposure = 450;
			else if (pO2 > 0.6)
				exposure = 570;
			else if (pO2 > 0.5)
				exposure = 720;
			else
				exposure = 0;
			
            if (exposure > 0)
				cns += time / exposure;
			
            if (pO2 > maxOx)
				maxOx = pO2;
			
            //System.out.println("OxTox: add "+time+" min on "+pO2+". OTU="+(int)otu+" CNS="+(int)(cns*100)+'\n');        
		}

		/// <summary> 
        /// Removes oxygen load from model during surface intervals.
        /// </summary>
		/// <param name="time">Time of segment in minutes</param>
		public virtual void RemoveO2(double time)
		{
			if (time >= 1440)
			{
				// 24 hrs
				otu = 0;
			}
			
            double cnsOld = cns;
			
            // Decay cns with a halftime of 90mins
			cns = cns * System.Math.Exp((- time) * 0.693147 / 90);
			
            //System.out.println("CNS decayed for"+time+". Was ="+cnsOld+", now="+cns);
        }

        #endregion
    }
}
